/*
 *  Copyright 2019-2020 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package me.zhengjie.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.RequiredArgsConstructor;
import me.zhengjie.domain.KwExam;
import me.zhengjie.exception.ParameterException;
import me.zhengjie.mapper.*;
import me.zhengjie.pojo.entity.*;
import me.zhengjie.pojo.export.ExamExport;
import me.zhengjie.repository.KwExamRepository;
import me.zhengjie.repository.KwOccupyRepository;
import me.zhengjie.service.KwExamService;
import me.zhengjie.service.dto.KwExamDto;
import me.zhengjie.service.dto.KwExamQueryCriteria;
import me.zhengjie.service.mapstruct.KwExamMapper;
import me.zhengjie.util.AssertUtils;
import me.zhengjie.util.KwUtils;
import me.zhengjie.util.ruoyiexcel.ExcelUtil;
import me.zhengjie.util.ruoyiexcel.StringUtils;
import me.zhengjie.utils.*;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author LongYang
 * @website https://el-admin.vip
 * @description 服务实现
 * @date 2021-06-28
 **/
@Service
@RequiredArgsConstructor
public class KwExamServiceImpl implements KwExamService {

    private final KwExamRepository kwExamRepository;
    private final KwExamMapper kwExamMapper;
    private final ExamMapper examMapper;
    private final KwOccupyRepository kwOccupyRepository;
    private final OccupyMapper occupyMapper;

    private final UserMapper userMapper;
    private final ExamPlanMapper examPlanMapper;
    private final ExamTeacherMapper examTeacherMapper;
    private final ExamRoomMapper examRoomMapper;
    private final ExamStudentMapper examStudentMapper;
    private final SysUsersRolesMapper sysUsersRolesMapper;
    private final KwUtils kwUtils;


    @Override
    public Map<String, Object> queryAll(KwExamQueryCriteria criteria, Pageable pageable) {
        Page<KwExam> page = kwExamRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
        /*获取当前登录用户*/
        UserDetails currentUser = SecurityUtils.getCurrentUser();
        String username = currentUser.getUsername();
        /*根据当前登陆用户名获取登录用户的部门id*/
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        User user = userMapper.selectOne(wrapper);

        /*如果用户是超级管理员则返回所有数据*/
        Page<KwExam> adminPage = findAll(page, user);
        if (adminPage != null) return PageUtil.toPage(adminPage.map(kwExamMapper::toDto));

        /*如果用户不是超级管理员，根据他的部门查询对应的考试任务计算人员数量*/
        Long deptId = user.getDeptId();
        if (deptId != null) {

            for (KwExam kwExam : page.getContent()) {
                /*根据当前登录用户id此次考试id获取本次考试需上报的监考教师数量*/
                Integer examId = kwExam.getId();
                QueryWrapper<ExamPlan> examPlanQueryWrapper = new QueryWrapper<>();
                examPlanQueryWrapper.eq("dept_id", deptId)
                        .eq("exam_id", examId);
                List<ExamPlan> examPlan = examPlanMapper.selectList(examPlanQueryWrapper);
                /*需上报的考务人员数量*/
                Integer reportStaffNumber = 0;
                /*需上报的监考人员数量*/
                Integer reportTeacherNumber = 0;
                if (examPlan != null && !examPlan.isEmpty()) {
                    for (ExamPlan plan : examPlan) {
                        reportStaffNumber += plan.getStaffNumber() != null ? plan.getStaffNumber() : 0;
                        reportTeacherNumber += plan.getTeacherNumber() != null ? plan.getTeacherNumber() : 0;
                    }
                }
                kwExam.setReportTeacherNumber(reportTeacherNumber);
                kwExam.setReportStaffNumber(reportStaffNumber);

                /*获取本次考试的本学院监考教师数量*/
                QueryWrapper<ExamTeacher> examTeacherQueryWrapper = new QueryWrapper<>();
                examTeacherQueryWrapper.eq("exam_id", examId)
                        .eq("dept_id", deptId)
                        .select("distinct (teacher_id), identity ");
//                        .groupBy("teacher_id");
                List<ExamTeacher> examTeachers = examTeacherMapper.selectList(examTeacherQueryWrapper);
                if (examTeachers != null && !examTeachers.isEmpty()) {
                    /*统计本学院本次考试上报的监考人员数量*/
//                    List<ExamTeacher> reportedTeacherList = examTeachers.stream().filter(examTeacher -> StringUtils.isNotBlank(examTeacher.getIdentity())).filter(examTeacher -> Objects.equals(examTeacher.getIdentity(), "0")).collect(Collectors.toList());
                    List<ExamTeacher> reportedTeacherList = examTeachers.stream().filter(examTeacher -> StringUtils.isNotBlank(examTeacher.getIdentity())).filter(examTeacher -> examTeacher.getIdentity().contains("0")).collect(Collectors.toList());
                    /*统计本学院本次考试上报的考务人员数量*/
//                    List<ExamTeacher> reportedStaffList = examTeachers.stream().filter(examTeacher -> StringUtils.isNotBlank(examTeacher.getIdentity())).filter(examTeacher -> Objects.equals(examTeacher.getIdentity(), "1")).collect(Collectors.toList());
                    List<ExamTeacher> reportedStaffList = examTeachers.stream().filter(examTeacher -> StringUtils.isNotBlank(examTeacher.getIdentity())).filter(examTeacher -> examTeacher.getIdentity().contains("1")).collect(Collectors.toList());
                    kwExam.setReportedStaffCount(reportedStaffList != null && !reportedStaffList.isEmpty() ? reportedStaffList.size() : 0);
                    kwExam.setReportedTeacherCount(reportedTeacherList != null && !reportedTeacherList.isEmpty() ? reportedTeacherList.size() : 0);
                } else {
                    kwExam.setReportedStaffCount(0);
                    kwExam.setReportedTeacherCount(0);
                }
            }
        }
        return PageUtil.toPage(page.map(kwExamMapper::toDto));
    }

    /**
     * 如果账号的角色是超级管理员（role_id=1），忽视部门，
     * 计算出所有考试的所有考试任务的需上报数量和已上报数量
     *
     * @return 如果用户不是超级管理员会返回null值, 是超级管理员则会返回所有考试并附带计算出的需上报人员数量和已上报人员数量
     */
    private Page<KwExam> findAll(Page<KwExam> page, User user) {
        QueryWrapper<SysUsersRoles> usersRolesQueryWrapper = new QueryWrapper<>();
        usersRolesQueryWrapper.eq("user_id", user.getUserId())
                .eq("role_id", 1);
        List<SysUsersRoles> sysUsersRoles = sysUsersRolesMapper.selectList(usersRolesQueryWrapper);
        /*如果用户不是超级管理员不计算全部需上报数量和已上报数量*/
        if (sysUsersRoles == null || sysUsersRoles.isEmpty()) return null;
        for (KwExam kwExam : page.getContent()) {
            Integer examId = kwExam.getId();
            /*查询出这次考试的所有部门考试任务*/
            QueryWrapper<ExamPlan> examPlanQueryWrapper = new QueryWrapper<>();
            examPlanQueryWrapper.eq("exam_id", examId);
            List<ExamPlan> examPlan = examPlanMapper.selectList(examPlanQueryWrapper);
            /*需上报的考务人员数量*/
            Integer reportStaffNumber = 0;
            /*需上报的监考人员数量*/
            Integer reportTeacherNumber = 0;
            if (examPlan != null && !examPlan.isEmpty()) {
                for (ExamPlan plan : examPlan) {
                    reportStaffNumber += plan.getStaffNumber() != null ? plan.getStaffNumber() : 0;
                    reportTeacherNumber += plan.getTeacherNumber() != null ? plan.getTeacherNumber() : 0;
                }
            }
            kwExam.setReportTeacherNumber(reportTeacherNumber);
            kwExam.setReportStaffNumber(reportStaffNumber);

            /*获取本次考试的本学院监考教师数量*/
            QueryWrapper<ExamTeacher> examTeacherQueryWrapper = new QueryWrapper<>();
            examTeacherQueryWrapper.eq("exam_id", examId)
                    .select("distinct (teacher_id), identity ");
            List<ExamTeacher> examTeachers = examTeacherMapper.selectList(examTeacherQueryWrapper);
            if (examTeachers != null && !examTeachers.isEmpty()) {
                /*统计本学院本次考试上报的监考人员数量*/
                List<ExamTeacher> reportedTeacherList = examTeachers.stream().filter(examTeacher -> StringUtils.isNotBlank(examTeacher.getIdentity())).filter(examTeacher -> examTeacher.getIdentity().contains("0")).collect(Collectors.toList());
                /*统计本学院本次考试上报的考务人员数量*/
                List<ExamTeacher> reportedStaffList = examTeachers.stream().filter(examTeacher -> StringUtils.isNotBlank(examTeacher.getIdentity())).filter(examTeacher -> examTeacher.getIdentity().contains("1")).collect(Collectors.toList());
                kwExam.setReportedStaffCount(reportedStaffList != null && !reportedStaffList.isEmpty() ? reportedStaffList.size() : 0);
                kwExam.setReportedTeacherCount(reportedTeacherList != null && !reportedTeacherList.isEmpty() ? reportedTeacherList.size() : 0);
            } else {
                kwExam.setReportedStaffCount(0);
                kwExam.setReportedTeacherCount(0);
            }

        }
        return page;
    }


    @Override
    public List<KwExamDto> queryAll(KwExamQueryCriteria criteria) {
        return kwExamMapper.toDto(kwExamRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
    }

    @Override
    @Transactional
    public KwExamDto findById(Integer id) {
        KwExam kwExam = kwExamRepository.findById(id).orElseGet(KwExam::new);
        ValidationUtil.isNull(kwExam.getId(), "KwExam", "id", id);
        return kwExamMapper.toDto(kwExam);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public KwExamDto create(KwExam resources) {
        if (resources.getStartTime().getTime() > resources.getEndTime().getTime())
            throw new ParameterException("开始时间不可大于结束时间");
        return kwExamMapper.toDto(kwExamRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(KwExam resources) {
        if (resources.getStartTime().getTime() > resources.getEndTime().getTime())
            throw new ParameterException("开始时间不可大于结束时间");
        KwExam kwExam = kwExamRepository.findById(resources.getId()).orElseGet(KwExam::new);
        ValidationUtil.isNull(kwExam.getId(), "KwExam", "id", resources.getId());
        kwExam.copy(resources);

        kwExamRepository.save(kwExam);
        Date startTime = new Date(kwExam.getStartTime().getTime());
        Date endTime = new Date(kwExam.getEndTime().getTime());
        UpdateWrapper<Occupy> wrapper = new UpdateWrapper<>();
        wrapper.eq("exam_id", kwExam.getId())
                .set("start_time", startTime)
                .set("end_time", endTime);
        occupyMapper.update(null, wrapper);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(Integer[] ids) {
        boolean permission = kwUtils.hasOtherPermission(Arrays.asList(ids));
        if (!permission) throw new ParameterException("无权操作");
        for (Integer id : ids) {
            QueryWrapper<ExamPlan> examPlanQueryWrapper = new QueryWrapper<>();
            examPlanQueryWrapper.eq("exam_id", id);
            examPlanMapper.delete(examPlanQueryWrapper);

            QueryWrapper<ExamRoom> examRoomQueryWrapper = new QueryWrapper<>();
            examRoomQueryWrapper.eq("exam_id", id);
            examRoomMapper.delete(examRoomQueryWrapper);

            QueryWrapper<ExamStudent> examStudentQueryWrapper = new QueryWrapper<>();
            examStudentQueryWrapper.eq("exam_id", id);
            examStudentMapper.delete(examStudentQueryWrapper);

            QueryWrapper<ExamTeacher> examTeacherQueryWrapper = new QueryWrapper<>();
            examTeacherQueryWrapper.eq("exam_id", id);
            examTeacherMapper.delete(examTeacherQueryWrapper);

            QueryWrapper<Occupy> occupyQueryWrapper = new QueryWrapper<>();
            occupyQueryWrapper.eq("exam_id", id);
            occupyMapper.delete(occupyQueryWrapper);

            kwExamRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<KwExamDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (KwExamDto kwExam : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("考试名称", kwExam.getNameCn());
            map.put("地点", kwExam.getAddress());
            map.put("开始时间", kwExam.getStartTime());
            map.put("结束时间", kwExam.getEndTime());
            map.put("状态(0：正常，1：结束)", kwExam.getStatus());
            map.put("本次监考老师人数", kwExam.getTeacherCount());
            map.put("删除标识（0：未删除，2：已删除）", kwExam.getDelFlag());
            map.put("考试公开信息id(暂不使用，此处添加为预防)", kwExam.getPublicExamId());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public void export(HttpServletResponse response, List<Exam> exams) {
        LinkedList<ExamExport> list = new LinkedList<>();
        if (exams == null || exams.size() == 0) {
            exams = examMapper.selectList(null);
        }
        AssertUtils.isNotEmpty(exams, "无任何信息可导出");

        for (Exam exam : exams) {
            ExamExport examExport = new ExamExport();
            BeanUtils.copyProperties(exam, examExport);
            list.add(examExport);
        }
        ExcelUtil<ExamExport> excelUtil = new ExcelUtil<>(ExamExport.class);
        try {
            excelUtil.exportExcel(response, list, "考试信息");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 查询总考试下的的所有考试不分页
     *
     * @param generalId
     * @return
     */
    @Override
    public List<Exam> findALl(Long generalId) {
        QueryWrapper<Exam> wrapper = new QueryWrapper<>();
        wrapper.eq(generalId != null, "general_id", generalId);
        return examMapper.selectList(wrapper);
    }


}